package com.nwcl.ysx.controller;

import com.nwcl.basic.bo.UserBO;
import com.nwcl.basic.bo.UserIntegralBO;
import com.nwcl.basic.bo.UserIntegralFlowBO;
import com.nwcl.basic.service.UserIntegralFlowService;
import com.nwcl.basic.service.UserIntegralService;
import com.nwcl.basic.service.UserService;
import com.nwcl.common.constant.Constant;
import com.nwcl.common.result.Page;
import com.nwcl.common.result.Result;
import com.nwcl.common.utils.DateUtil;
import com.nwcl.common.utils.SessionUtil;
import com.nwcl.ysx.bo.RestaurantRoomBO;
import com.nwcl.ysx.bo.RestaurantRoomSubscribeBO;
import com.nwcl.ysx.bo.SubscribeBO;
import com.nwcl.ysx.request.CancelSubscribeRequest;
import com.nwcl.ysx.request.RoomSubPageRequest;
import com.nwcl.ysx.request.RoomSubscribeRequest;
import com.nwcl.ysx.service.RestaurantRoomService;
import com.nwcl.ysx.service.RestaurantRoomSubscribeService;
import com.nwcl.ysx.service.SubscribeService;
import com.nwcl.ysx.vo.SubscribeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author liguiqin
 * @date 2023/5/26
 */
@RestController
@RequestMapping("/api/ysx/subscribe")
public class ApiSubscribeController {
    @Autowired
    private SessionUtil sessionUtil;
    @Autowired
    private RestaurantRoomService restaurantRoomService;
    @Autowired
    private SubscribeService subscribeService;
    @Autowired
    private RestaurantRoomSubscribeService restaurantRoomSubscribeService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserIntegralService userIntegralService;
    @Autowired
    private UserIntegralFlowService userIntegralFlowService;

    /*
     * @Description: 包房预约列表
     * @Author liguiqin
     * @Date 2023/5/26 11:47
     * @param: request
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/26 11:47
     **/
    @GetMapping("/list")
    public Result list(RoomSubPageRequest param, HttpServletRequest request) {
        Page<SubscribeVO> resultPage = new Page<>();
        Integer userId = sessionUtil.getUserId(request);
        param.setUserId(userId);
        Page<SubscribeBO> page = subscribeService.page(param);
        List<SubscribeVO> voList = warpList(page.getList());
        resultPage = new Page<>(page.getPageNum(), page.getPageSize(), page.getTotal(), voList);
        return Result.success(resultPage);
    }


    /*
     * @Description: 包房预约
     * @Author liguiqin
     * @Date 2023/5/26 10:01
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/26 10:01
     **/
    @PostMapping("/roomSubscribe")
    public Result roomSubscribe(@RequestBody RoomSubscribeRequest param, HttpServletRequest request) {
        //校验参数
        Result rs = param.check();
        if (rs != null) {
            return rs;
        }
        //校验包房是否可预约
        RestaurantRoomBO room = restaurantRoomService.getById(param.getRoomId());
        rs = validRoom(room, param);
        if (rs != null) {
            return rs;
        }
        Integer userId = sessionUtil.getUserId(request);
        //保存预约信息
        SubscribeBO subscribeBO = getSubscribeBO(param, userId);
        Integer subscribeId = subscribeService.save(subscribeBO);
        //保存包房预约信息
        RestaurantRoomSubscribeBO roomSubscribeBO = getRestaurantRoomSubscribeBO(param, room, subscribeId);
        restaurantRoomSubscribeService.save(roomSubscribeBO);
        //发放积分
        saveUserIntegral(userId);
        //积分流水
        saveUserIntegralFlow(userId);
        return Result.success();
    }



    /*
     * @Description:取消预约
     * @Author liguiqin
     * @Date 2023/5/30 15:00
     * @param: param
     * @param: request
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/30 15:00
     **/
    @PostMapping("/cancel")
    public Result cancel(@RequestBody CancelSubscribeRequest param, HttpServletRequest request) {
        List<SubscribeBO> subscribeBOS = subscribeService.listByIds(Arrays.asList(param.getId()), Constant.SubscribeStatus.normal);
        if (CollectionUtils.isEmpty(subscribeBOS)) {
            return Result.fail("预约不存在");
        }
        SubscribeBO subscribeBO = subscribeBOS.get(0);
        if (subscribeBO.getUserId() != sessionUtil.getUserId(request)) {
            return Result.fail("预约不存在");
        }
        RestaurantRoomSubscribeBO roomSubscribeBO = restaurantRoomSubscribeService.getBySubscribeId(subscribeBO.getId());
        if (roomSubscribeBO != null && new Date().getTime() > roomSubscribeBO.getStartTime().getTime()) {
            return Result.fail("预约时间已过，不能取消");
        }
        subscribeService.updateStatusById(subscribeBO.getId(), Constant.SubscribeStatus.cancel);
        return Result.success();
    }

    /*
     * @Description: 校验包房是否可预约
     * @Author liguiqin
     * @Date 2023/5/26 11:11
     * @param: param
     * @return com.nwcl.common.result.Result
     * @UpdateDate 2023/5/26 11:11
     **/
    private Result validRoom(RestaurantRoomBO room, RoomSubscribeRequest param) {
        if (room == null) {
            return Result.fail("包房不存在");
        }
        //根据时间查询包房预约记录,判断是否有时间冲突
        List<RestaurantRoomSubscribeBO> roomSubscribeBOS = restaurantRoomSubscribeService.listTimeRangeOverlapping(room.getRestaurantId(), room.getId(), param.getStartTime(), param.getEndTime());
        if (CollectionUtils.isEmpty(roomSubscribeBOS)) {
            return null;
        }
        //如果有预约记录,判断预约状态是否为正常
        List<Integer> subscribeIds = new ArrayList<>();
        Map<Integer, RestaurantRoomSubscribeBO> roomSubscribeMap = new HashMap<>();
        for (RestaurantRoomSubscribeBO roomSubscribeBO : roomSubscribeBOS) {
            subscribeIds.add(roomSubscribeBO.getSubscribeId());
            roomSubscribeMap.put(roomSubscribeBO.getSubscribeId(), roomSubscribeBO);
        }
        List<SubscribeBO> subscribeBOS = subscribeService.listByIds(subscribeIds, Constant.SubscribeStatus.normal);
        //提示预约时间段已被预约
        if (!CollectionUtils.isEmpty(subscribeBOS)) {
            StringBuilder sb = new StringBuilder();
            for (SubscribeBO subscribeBO : subscribeBOS) {
                RestaurantRoomSubscribeBO roomSubscribeBO = roomSubscribeMap.get(subscribeBO.getId());
                sb.append(DateUtil.formatTime(roomSubscribeBO.getStartTime())).append("至").append(DateUtil.formatTime(roomSubscribeBO.getEndTime())).append(";");
            }
            return Result.fail("包房已被预约,时间段为:" + sb);
        }
        return null;
    }

    /*
     * @Description: 预约列表数据封装
     * @Author liguiqin
     * @Date 2023/5/29 11:32
     * @param: list
     * @return java.util.List<com.nwcl.ysx.vo.SubscribeVO>
     * @UpdateDate 2023/5/29 11:32
     **/
    private List<SubscribeVO> warpList(List<SubscribeBO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<SubscribeVO> voList = new ArrayList<>();
        List<Integer> userIds = new ArrayList<>();
        for (SubscribeBO bo : list) {
            userIds.add(bo.getUserId());
        }
        Map<Integer, UserBO> userMap = userService.mapByIds(userIds);
        for (SubscribeBO bo : list) {
            SubscribeVO vo = new SubscribeVO();
            vo.setId(bo.getId());
            vo.setPhone(bo.getPhone());
            vo.setSubTime(DateUtil.formatDateTime(bo.getSubTime()));
            vo.setBusinessType(bo.getBusinessType());
            vo.setBusinessTypeStr(Constant.SubscribeBusinessType.valMap.get(bo.getBusinessType()));
            vo.setStatus(bo.getStatus());
            vo.setStatusStr(Constant.SubscribeStatus.valMap.get(bo.getStatus()));
            vo.setRemark(bo.getRemark());
            vo.setUsername(userMap.get(bo.getUserId()).getUsername());
            voList.add(vo);
        }
        return voList;
    }



    /*
     * @Description: 保存用户积分
     * @Author liguiqin
     * @Date 2023/5/31 10:26
     * @param: userId
     * @return void
     * @UpdateDate 2023/5/31 10:26
     **/
    private void saveUserIntegral(Integer userId) {
        UserIntegralBO userIntegralBO = new UserIntegralBO();
        userIntegralBO.setUserId(userId);
        userIntegralBO.setIntegral(new BigDecimal(100));
        userIntegralBO.setStartTime(new Date());
        userIntegralBO.setEndTime(DateUtil.getMaxDate());
        userIntegralBO.setCreateTime(new Date());
        userIntegralBO.setUpdateTime(new Date());
        userIntegralBO.setIsValid(Constant.isValid.valid);
        userIntegralService.save(userIntegralBO);
    }
    /*
     * @Description: 保存积分流水
     * @Author liguiqin
     * @Date 2023/5/31 10:26
     * @param: userId
     * @return void
     * @UpdateDate 2023/5/31 10:26
     **/
    private void saveUserIntegralFlow(Integer userId) {
        UserIntegralFlowBO flow = new UserIntegralFlowBO();
        flow.setUserId(userId);
        flow.setType(Constant.UserIntegralFlowType.sub);
        flow.setBusinessType(Constant.UserIntegralFlowBusinessType.cash);
        flow.setIntegral(new BigDecimal(100));
        flow.setOrderId(null);
        flow.setCreateTime(new Date());
        flow.setUpdateTime(new Date());
        flow.setIsValid(Constant.isValid.valid);
        userIntegralFlowService.save(flow);
    }

    private RestaurantRoomSubscribeBO getRestaurantRoomSubscribeBO(RoomSubscribeRequest param, RestaurantRoomBO room, Integer subscribeId) {
        RestaurantRoomSubscribeBO roomSubscribeBO = new RestaurantRoomSubscribeBO();
        roomSubscribeBO.setSubscribeId(subscribeId);
        roomSubscribeBO.setRoomId(room.getId());
        roomSubscribeBO.setRestaurantId(room.getRestaurantId());
        roomSubscribeBO.setStartTime(DateUtil.parseDateTime(param.getStartTime()));
        roomSubscribeBO.setEndTime(DateUtil.parseDateTime(param.getEndTime()));
        roomSubscribeBO.setPeople(param.getPeople());
        roomSubscribeBO.setCreateTime(new Date());
        roomSubscribeBO.setUpdateTime(new Date());
        roomSubscribeBO.setIsValid(Constant.isValid.valid);
        return roomSubscribeBO;
    }

    private SubscribeBO getSubscribeBO(RoomSubscribeRequest param, Integer userId) {
        SubscribeBO subscribeBO = new SubscribeBO();
        subscribeBO.setPhone(param.getPhone());
        subscribeBO.setSubTime(new Date());
        subscribeBO.setBusinessType(Constant.SubscribeBusinessType.room);
        subscribeBO.setStatus(Constant.SubscribeStatus.normal);
        subscribeBO.setRemark(param.getRemark());
        subscribeBO.setCreateTime(new Date());
        subscribeBO.setUpdateTime(new Date());
        subscribeBO.setIsValid(Constant.isValid.valid);
        subscribeBO.setUserId(userId);
        return subscribeBO;
    }
}
